package com.tarena.lbs.basic.web.service;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.basic.web.dao.repository.AdminRepository;
import com.tarena.lbs.basic.web.dao.repository.BusinessRepository;
import com.tarena.lbs.basic.web.dao.repository.StoreRepository;
import com.tarena.lbs.basic.web.thread.AuthenticationUtil;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.pojo.attach.param.PicUpdateParam;
import com.tarena.lbs.pojo.basic.param.BusinessParam;
import com.tarena.lbs.pojo.basic.po.AdminPO;
import com.tarena.lbs.pojo.basic.po.BusinessPO;
import com.tarena.lbs.pojo.basic.po.StorePO;
import com.tarena.lbs.pojo.basic.query.BusinessQuery;
import com.tarena.lbs.pojo.basic.vo.BusiStoreVO;
import com.tarena.lbs.pojo.basic.vo.BusinessVO;
import com.tarena.lbs.pojo.basic.vo.StoreVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BusinessService {
    //lbs_business 每一个表格 都准备一套数据层
    @Autowired
    private BusinessRepository businessRepository;
    @Autowired
    private AdminRepository adminRepository;
    //注入一个店铺的仓储层
    @Autowired
    private StoreRepository storeRepository;
    public PageResult<BusinessVO> businessPage(BusinessQuery query) throws BusinessException {
        //数据权限调整 判断角色 如果是SHOP 使用用户id 查询商家businessId 放到query
        UserPrinciple userPrinciple = AuthenticationUtil.get();
        Asserts.isTrue(userPrinciple== null, new BusinessException("-2","认证解析失败"));
        if (userPrinciple.getRole()==Roles.SHOP){
            Integer adminId = userPrinciple.getId();
            AdminPO adminPO = adminRepository.getById(adminId);
            Asserts.isTrue(adminPO==null,new BusinessException("-2","登录商家账号不存在"));
            //query存放一个 当前登录账号所属的商家id字段属性
            query.setBusinessId(adminPO.getBusinessId());
        }
        //1.total objects 封装pageResult
        PageResult<BusinessVO> voPage=new PageResult<>();
        //2.封装现成数据 pageNo pageSize
        voPage.setPageNo(query.getPageNo());
        voPage.setPageSize(query.getPageSize());
        //phone name  where phone=#{} and name like concat(% #{name} %)
        //Long total=getBusinessTotal(query);
        //2.1调用仓储层 查询分页数据 返回值 包含total和pos
        PageInfo<BusinessPO> pageInfo = businessRepository.businessPage(query);
        voPage.setTotal(pageInfo.getTotal());
        List<BusinessPO> pos = pageInfo.getList();
        //List<BusinessPO> pos= getBusinessList(query);
        //3.封装vos 使用list的stream() api forEach filter map sort...
        List<BusinessVO> vos=null;
        if (pos!=null&&pos.size()>0){
            vos=pos.stream().map(po->{
                //映射计算 每一个po元素转化成vo
                BusinessVO vo=new BusinessVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        voPage.setObjects(vos);
        return voPage;
    }

    private List<BusinessPO> getBusinessList(BusinessQuery query) {
        Integer from=(query.getPageNo()-1)*query.getPageSize();
        return businessRepository.getPageList(from,query.getPageSize());
    }

    private Long getBusinessTotal(BusinessQuery query) {
        //查询所有 暂时不关心业务条件
        return businessRepository.count();
    }
    @Transactional(rollbackFor = Exception.class)//本地事务 注解 只对RuntimeException做默认回滚
    public void save(BusinessParam param) throws BusinessException {
        //1.检验业务权限 是否满足用户角色=Roles.admin
        checkRole(Roles.ADMIN);
        //2.保证幂等
        checkMideng(param);
        //3.封装po 调用仓储层写入
        BusinessPO poParam=param2po(param);
        log.info("新增写入之前,po的id:{}",poParam.getId());
        //持久层mybatis-plus框架 会根据 po对象的注解 @TableId(value = "id", type = IdType.AUTO)
        //mybatis-plus新增po之后 会给id自增数据回填到po对象中
        businessRepository.save(poParam);
        log.info("新增写入之后,po的id:{}",poParam.getId());
        //4.远程调用,图片绑定
        bindPictures(poParam);
    }
    @DubboReference(retries = 5)
    private AttachApi attachApi;
    private void bindPictures(BusinessPO poParam) throws BusinessException {
        //这里全部的代码都围绕着 接口方法batchUpdateBusiness完成
        //1.封装入参 当前商家businessType businessId 绑定2个图片 商家营业执照 商家logo
        List<PicUpdateParam> picParams=new ArrayList<>();
        //1.1在入参中 先准备营业执照的绑定属性
        PicUpdateParam licenseParam=new PicUpdateParam();
        //设置商家营业执照的 业务类型 100
        licenseParam.setBusinessType(100);
        licenseParam.setBusinessId(poParam.getId());
        //商家属性中有2个url地址 http://localhost:9081/static/{3F932JRF329F923RG23.PNG}
        String licensefileUuid=parseUrlFillUuid(poParam.getBusinessLicense());
        licenseParam.setFileUuid(licensefileUuid);
        picParams.add(licenseParam);
        //1.2在入参中 准备商家logo图片
        PicUpdateParam logoParam=new PicUpdateParam();
        //设置商家营业执照的 业务类型 100
        logoParam.setBusinessType(200);
        logoParam.setBusinessId(poParam.getId());
        //商家属性中有2个url地址 http://localhost:9081/static/{3F932JRF329F923RG23.PNG}
        String logofileUuid=parseUrlFillUuid(poParam.getBusinessLogo());
        logoParam.setFileUuid(logofileUuid);
        picParams.add(logoParam);
        //2.直接调用 attach接口 完成入参传递 接收出参返回值
        try {
            boolean result = attachApi.batchUpdateBusiness(picParams);
            Asserts.isTrue(!result,new BusinessException("-2","图片绑定失败"));
        }catch (Exception e){
            log.error("当前商家:{},绑定图片:{},异常失败",poParam,picParams,e);
            //如果 简单设计一个强一致性的事务 这里可以向外抛出异常
            throw new BusinessException("-2","远程调用图片失败");
        }
    }

    private String parseUrlFillUuid(String url) throws BusinessException {
        //1.使用基础api 从url解析fileUuid 先判断非空
        if (StringUtils.isNotEmpty(url)){
            //2.切字符串 /
            String[] components = url.split("/");
            if (components!=null&&components.length>0){
                //返回最后一个元素
                return components[components.length-1];
            }
        }
        log.error("解析url失败,url:{}",url);
        throw new BusinessException("-2","绑定图片数据异常");
    }

    private BusinessPO param2po(BusinessParam param) {
        //1.创建po
        BusinessPO po=new BusinessPO();
        //2.能拷贝的先拷贝
        BeanUtils.copyProperties(param,po);
        //3.手动补充 param不存在 但是需要填补数据
        //3.1auditRemarks 审核意见
        po.setAuditRemarks("通过");
        //3.2businessStatus 1待审核 2通过 3驳回
        po.setBusinessStatus(2);
        //3.3entryTime 注册时间
        po.setEntryTime(new Date());
        return po;
    }

    private void checkMideng(BusinessParam param) throws BusinessException {
        //直接使用param中的businessName 查询是否存在 存在抛异常 结束 不存在 允许后续新增
        String businessName = param.getBusinessName();
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("business_name",businessName);
        long count = businessRepository.count(queryWrapper);
        Asserts.isTrue(count>0,new BusinessException("-2","商家名称已存在"));
    }

    private void checkRole(Roles roles) throws BusinessException {
        //1.拿到登录用身份
        UserPrinciple userPrinciple = AuthenticationUtil.get();
        //2.断言 拿不到
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","认证解析失败"));
        //3.断言 登录身份和要求身份是否一致
        Asserts.isTrue(!(userPrinciple.getRole()==roles),new BusinessException("-2","权限不足"));
    }

    public BusiStoreVO businessStores(Integer businessId) throws BusinessException {
        //1.查询商家数据 用id
        BusinessPO businessPO = businessRepository.getById(businessId);
        Asserts.isTrue(businessPO==null,new BusinessException("-2","商家不存在"));
        //2.当前接口的入参设计 无法查询 所属活动绑定的店铺列表 利用商家id查询所有店铺
        List<StorePO> storePos=getBusinessStores(businessId);
        //3.转化
        BusiStoreVO vo=new BusiStoreVO();
        BeanUtils.copyProperties(businessPO,vo);
        //storeVOList缺少
        List<StoreVO> storeVos=null;
        if (CollectionUtils.isNotEmpty(storePos)){
            storeVos=storePos.stream().map(po->{
                StoreVO sVo=new StoreVO();
                BeanUtils.copyProperties(po,sVo);
                return sVo;
            }).collect(Collectors.toList());
        }
        vo.setStoreVOList(storeVos);
        return vo;
    }

    private List<StorePO> getBusinessStores(Integer businessId) {
        //select * from lbs_store where business_id=#{}
        QueryWrapper<StorePO> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("business_id",businessId);
        return storeRepository.list(queryWrapper);
    }
}
